package com.cjkj.system.service.impl;

import com.cjkj.common.core.constant.EquipmentConstants;
import com.cjkj.common.core.constant.SecurityConstants;
import com.cjkj.common.core.domain.PatVisitIntervalData;
import com.cjkj.common.core.domain.R;
import com.cjkj.common.core.exception.ServiceException;
import com.cjkj.common.core.utils.StringUtils;
import com.cjkj.system.api.RemoteTJ03DataService;
import com.cjkj.system.api.domain.APITJ03BpData;
import com.cjkj.system.api.domain.APITJ03EcgData;
import com.cjkj.system.api.domain.APITJ03HrData;
import com.cjkj.system.api.domain.request.RecordsReq;
import com.cjkj.system.domain.TEquipmentUsageRecords;
import com.cjkj.system.domain.TPatVisit;
import com.cjkj.system.domain.vo.ScreenSignVo;
import com.cjkj.system.domain.vo.report.*;
import com.cjkj.system.mapper.TEquipmentUsageRecordsMapper;
import com.cjkj.system.mapper.TPatVisitMapper;
import com.cjkj.system.service.ReportTJ03Service;
import com.cjkj.system.util.ReportUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ReportTJ03ServiceImpl implements ReportTJ03Service {

    @Resource
    private TPatVisitMapper patVisitMapper;

    @Resource
    private TEquipmentUsageRecordsMapper equipmentUsageRecordsMapper;

    @Resource
    private RemoteTJ03DataService remoteTJ03DataService;

    @Override
    public HeartRateReportVo getTJ03HeartRateReports(Long visitNo) {
        // 获取患者开单时间和出院时间
        PatVisitIntervalData intervalTimes = getTimes(visitNo);
        Date visitTime = intervalTimes.getVisitTime();
        Date outTime = intervalTimes.getOutTime();

        // 查询监测数据
        List<APITJ03HrData> hrDataList = new ArrayList<>();
        List<TEquipmentUsageRecords> usageRecordsList = equipmentUsageRecordsMapper.selectAllUseRecordByVisitNo(visitNo);
        for (TEquipmentUsageRecords usageRecord : usageRecordsList) {
            if (usageRecord != null && EquipmentConstants.EQUIPMENT_TYPE_EB_TYPE.equals(usageRecord.getEquipmentType())) {
                Date startTime = usageRecord.getStartTime();
                Date endTime = usageRecord.getEndTime();
                endTime = (endTime == null || endTime.after(outTime)) ? outTime : endTime;

                //查询设备在该时间段采集的数据
                hrDataList.addAll(remoteReportTj03HrDataList(usageRecord.getEquipmentNo(), startTime, endTime));
            }
        }
        if (hrDataList.isEmpty()) {
            return new HeartRateReportVo();
        }

        // 获取第一条数据
        APITJ03HrData apitj03HrData = hrDataList.get(0);
        Date createTime = new Date(apitj03HrData.getCreateTime());
        // 获取开始时间
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(createTime);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Date start = calendar.getTime();
        // 获取结束时间
        calendar.add(Calendar.MINUTE, 1);
        calendar.set(Calendar.MILLISECOND, 999);
        Date end = calendar.getTime();

        // 生成报告数据
        List<Date> abscissa = new ArrayList<>();
        List<Integer> axis = new ArrayList<>();
        while (!hrDataList.isEmpty()) {
            // 筛选出对应时间段的数据
            Date finalStart = start, finalEnd = end;
            List<APITJ03HrData> intervalData = hrDataList.stream()
                    .sorted(Comparator.comparing(APITJ03HrData::getCreateTime))
                    .filter(e -> e.getCreateTime() >= finalStart.getTime() && e.getCreateTime() <= finalEnd.getTime())
                    .collect(Collectors.toList());

            int minuteHr = 0;
            if(! intervalData.isEmpty()) {
                // 求这分钟数据的众数
                List<Integer> heartData = intervalData.stream()
                        .map(APITJ03HrData::getHr)
                        .filter(e -> e > 0 && e < 220)
                        .collect(Collectors.toList());
                if(! heartData.isEmpty()) {
                    minuteHr = (int) Math.ceil(ReportUtil.getAvg(heartData));
                }
            }
            abscissa.add(start);
            axis.add(minuteHr);

            // 设置时间
            start = end;
            Calendar oneM = Calendar.getInstance();
            oneM.setTime(start);
            oneM.add(Calendar.MINUTE, 1);
            end = oneM.getTime();
            // 移除
            hrDataList.removeAll(intervalData);
        }

        HeartRateReportVo heartRateReportVo = new HeartRateReportVo();
        heartRateReportVo.setReportTime(visitTime);
        heartRateReportVo.setAbscissa(abscissa);
        heartRateReportVo.setHeartRateAxis(axis);
        heartRateReportVo.setHighestHeartRate(axis.stream().mapToInt(Integer::intValue).max().orElse(0));
        heartRateReportVo.setLowestHeartRate(axis.stream().filter(e -> e != 0).mapToInt(Integer::intValue).min().orElse(0));
        heartRateReportVo.setAvgHeartRate((int) axis.stream().filter(e -> e != 0).mapToInt(Integer::intValue).average().orElse(0));
        return heartRateReportVo;
    }

    /**
     * 远程请求多参数监测仪数据
     * @param equipmentNo 设备号
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 监测数据
     */
    private List<APITJ03HrData> remoteReportTj03HrDataList(String equipmentNo, Date startTime, Date endTime) {

        List<APITJ03HrData> hrData = new ArrayList<>();
        // 组装参数
        RecordsReq recordsReq = new RecordsReq();
        recordsReq.setEquipmentNo(equipmentNo);
        recordsReq.setStartTime(startTime);
        recordsReq.setEndTime(endTime);
        // 远程请求数据
        R<List<APITJ03HrData>> hrRecordRes = remoteTJ03DataService.tj03HrRecords(recordsReq, SecurityConstants.INNER);
        if (StringUtils.isNotNull(hrRecordRes)) {
            if (R.FAIL == hrRecordRes.getCode()
                    || StringUtils.isNull(hrRecordRes.getData())) {
                log.error("查询设备采集数据出错：" + equipmentNo + "," + startTime + "-" + endTime);
                return hrData;
            }

            hrData = hrRecordRes.getData();
        } else {
            log.error("查询设备采集数据出错：" + equipmentNo + "," + startTime + "-" + endTime);
        }
        return hrData;
    }

    @Override
    public List<BloodPressureReportVo> getTJ03BloodPressureReports(Long visitNo) {
        // 获取患者开单时间和出院时间
        PatVisitIntervalData intervalData = getTimes(visitNo);
        Date outTime = intervalData.getOutTime();

        // 查询监测数据
        List<APITJ03BpData> bpDataList = new ArrayList<>();
        List<TEquipmentUsageRecords> usageRecordsList = equipmentUsageRecordsMapper.selectAllUseRecordByVisitNo(visitNo);
        for (TEquipmentUsageRecords usageRecord : usageRecordsList) {
            if (usageRecord != null && EquipmentConstants.EQUIPMENT_TYPE_EB_TYPE.equals(usageRecord.getEquipmentType())) {
                Date startTime = usageRecord.getStartTime();
                Date endTime = usageRecord.getEndTime();
                endTime = (endTime == null || endTime.after(outTime)) ? outTime : endTime;

                //查询设备在该时间段采集的数据
                bpDataList.addAll(remoteReportTj03BpDataList(usageRecord.getEquipmentNo(), startTime, endTime));
            }
        }
        if (bpDataList.isEmpty()) {
            return null;
        }

        // 返回报告数据
        List<BloodPressureReportVo> reportVoList = new ArrayList<>();
        for (APITJ03BpData bpData : bpDataList) {
            BloodPressureReportVo reportVo = new BloodPressureReportVo();
            reportVo.setTime(bpData.getCreateTime());
            reportVo.setStatus(bpData.getBptStatus());
            reportVo.setSbp(bpData.getSbp());
            reportVo.setDbp(bpData.getDbp());
            reportVoList.add(reportVo);
        }
        return reportVoList;
    }
    private List<APITJ03BpData> remoteReportTj03BpDataList(String equipmentNo, Date startTime, Date endTime) {
        List<APITJ03BpData> bpData = new ArrayList<>();
        // 组装参数
        RecordsReq recordsReq = new RecordsReq();
        recordsReq.setEquipmentNo(equipmentNo);
        recordsReq.setStartTime(startTime);
        recordsReq.setEndTime(endTime);
        // 远程请求数据
        R<List<APITJ03BpData>> bpRecordRes = remoteTJ03DataService.tj03BpRecords(recordsReq, SecurityConstants.INNER);
        if (StringUtils.isNotNull(bpRecordRes)) {
            if (R.FAIL == bpRecordRes.getCode()
                    || StringUtils.isNull(bpRecordRes.getData())) {
                log.error("查询设备采集数据出错：" + equipmentNo + "," + startTime + "-" + endTime);
                return bpData;
            }

            bpData = bpRecordRes.getData();
        } else {
            log.error("查询设备采集数据出错：" + equipmentNo + "," + startTime + "-" + endTime);
        }
        return bpData;
    }

    @Override
    public ECGReportVo getTJ03ECGReports(Long visitNo) {
        // 获取患者开单时间和出院时间
        PatVisitIntervalData intervalData = getTimes(visitNo);
        Date outTime = intervalData.getOutTime();

        // 获取使用的设备记录
        List<TEquipmentUsageRecords> usageRecordsList = equipmentUsageRecordsMapper.selectAllUseRecordByVisitNo(visitNo);

        // 获取最新一条心率数据的时间
        List<TEquipmentUsageRecords> reverseOrderData = usageRecordsList.stream().sorted(Comparator.comparing(TEquipmentUsageRecords::getStartTime).reversed()).collect(Collectors.toList());
        Date lastHrTime = null;
        for (TEquipmentUsageRecords usageRecord : reverseOrderData) {
            if (usageRecord != null && EquipmentConstants.EQUIPMENT_TYPE_EB_TYPE.equals(usageRecord.getEquipmentType())) {
                Date startTime = usageRecord.getStartTime();
                Date endTime = usageRecord.getEndTime();
                endTime = (endTime == null || endTime.after(outTime)) ? outTime : endTime;

                // 组装参数
                RecordsReq recordsReq = new RecordsReq();
                recordsReq.setEquipmentNo(usageRecord.getEquipmentNo());
                recordsReq.setStartTime(startTime);
                recordsReq.setEndTime(endTime);
                R<APITJ03HrData> apitj03HrDataR = remoteTJ03DataService.tj03LatestHrData(recordsReq, SecurityConstants.INNER);
                if(R.SUCCESS == apitj03HrDataR.getCode() && StringUtils.isNotNull(apitj03HrDataR.getData())) {
                    APITJ03HrData data = apitj03HrDataR.getData();
                    lastHrTime = new Date(data.getCreateTime());
                }
            }
        }

        // 获取最新5分钟的心电数据
        List<APITJ03EcgData> allData = new ArrayList<>();
        if(lastHrTime != null) {
            long time = lastHrTime.getTime();
            time = time - 5 * 60 * 1000;
            // 五分钟前
            Date beforeTime = new Date(time);
            for (TEquipmentUsageRecords usageRecord : reverseOrderData) {
                if (usageRecord != null && EquipmentConstants.EQUIPMENT_TYPE_EB_TYPE.equals(usageRecord.getEquipmentType())) {
                    Date startTime = usageRecord.getStartTime();
                    //查询设备在该时间段采集的数据
                    allData.addAll(remoteReportTj03EcgDataList(usageRecord.getEquipmentNo(), (startTime.before(beforeTime) ? beforeTime : startTime), lastHrTime));
                }
            }
        }

        // 格式化心电数据
        List<ECGTimeValue> timeValues = new ArrayList<>();
        if(! allData.isEmpty()) {
            for (APITJ03EcgData ecgDataObj : allData) {
                String ecgData = ecgDataObj.getEcgData();
                long createTime = ecgDataObj.getCreateTime();
                if(StringUtils.isNotBlank(ecgData)) {
                    String[] split = ecgData.split(",");
                    long interval = 0L;
                    for (String s : split) {
                        timeValues.add(new ECGTimeValue(createTime - interval, Double.parseDouble(s) / 1000));
                        interval += 4L;
                    }
                }
            }
        }
        // 升序排序
        List<ECGTimeValue> sorted = timeValues.stream().sorted(Comparator.comparing(ECGTimeValue::getTime)).collect(Collectors.toList());

        // 返回报告
        List<Long> abscissa = sorted.stream().map(ECGTimeValue::getTime).collect(Collectors.toList());
        List<Double> axis = sorted.stream().map(ECGTimeValue::getValue).collect(Collectors.toList());
        ECGReportVo reportVo = new ECGReportVo();
        reportVo.setAbscissa(abscissa);
        reportVo.setAxis(axis);
        reportVo.setReportTime(outTime);
        return reportVo;
    }
    private List<APITJ03EcgData> remoteReportTj03EcgDataList(String equipmentNo, Date startTime, Date endTime) {
        List<APITJ03EcgData> ecgData = new ArrayList<>();
        // 组装参数
        RecordsReq recordsReq = new RecordsReq();
        recordsReq.setEquipmentNo(equipmentNo);
        recordsReq.setStartTime(startTime);
        recordsReq.setEndTime(endTime);
        // 远程请求数据
        R<List<APITJ03EcgData>> ecgRecordRes = remoteTJ03DataService.tj03ECGRecords(recordsReq, SecurityConstants.INNER);
        if (StringUtils.isNotNull(ecgRecordRes)) {
            if (R.FAIL == ecgRecordRes.getCode()
                    || StringUtils.isNull(ecgRecordRes.getData())) {
                log.error("查询设备采集数据出错：" + equipmentNo + "," + startTime + "-" + endTime);
                return ecgData;
            }

            ecgData = ecgRecordRes.getData();
        } else {
            log.error("查询设备采集数据出错：" + equipmentNo + "," + startTime + "-" + endTime);
        }
        return ecgData;
    }

    /**
     * 获取患者开单时间和出院时间
     * @param visitNo 患者开单号
     * @return 开单时间和出院时间
     */
    private PatVisitIntervalData getTimes(Long visitNo) {
        // 查询患者信息
        TPatVisit tPatVisit = patVisitMapper.selectTPatVisitByVisitNo(visitNo);
        if (tPatVisit == null) {
            throw new ServiceException("患者信息不存在！");
        }
        // 开单时间
        Date visitTime = tPatVisit.getVisitTime();
        // 出院时间
        Date outTime  = tPatVisit.getOutTime();
        return new PatVisitIntervalData(visitTime, outTime == null ? new Date() : outTime);
    }

    @Override
    public ScreenSignVo getPatTJ03Date(Long visitNo) {
        ScreenSignVo screenSignVo = new ScreenSignVo();

        // 心率
        HeartRateReportVo tj03HeartRateReports = getTJ03HeartRateReports(visitNo);
        if (tj03HeartRateReports != null) {
            HeartRateVo heartRateVo = new HeartRateVo();
            heartRateVo.setHeartRateAbscissa(tj03HeartRateReports.getAbscissa());
            heartRateVo.setHeartRateAxis(tj03HeartRateReports.getHeartRateAxis());

            screenSignVo.setHeartRateVo(heartRateVo);
        }

        // 血压
        List<BloodPressureReportVo> tj03BloodPressureReports = getTJ03BloodPressureReports(visitNo);
        if (tj03BloodPressureReports != null) {
            screenSignVo.setBpReportVoList(tj03BloodPressureReports);
        }

        return screenSignVo;
    }
}
